From bb56af11216d5386ba411f6c95d094f3a1492360 Mon Sep 17 00:00:00 2001 From: "sos22@labyrinth.cl.cam.ac.uk" Date: Thu, 3 Jul 2003 16:30:18 +0000 Subject: [PATCH] bitkeeper revision 1.259.1.1 (3f045a1aTKC1vRJU2nif7VHOWTRJ1g) New physical disk access control stuff. --- .rootkeys | 7 + tools/internal/Makefile | 17 +- tools/internal/physdev.h | 26 ++ tools/internal/xi_phys_grant.c | 43 +++ tools/internal/xi_phys_probe.c | 48 +++ tools/internal/xi_phys_revoke.c | 33 ++ xen/common/domain.c | 6 + xen/drivers/block/xen_block.c | 130 ++++++++ xen/drivers/block/xen_physdisk.c | 301 ++++++++++++++++++ xen/include/hypervisor-ifs/block.h | 26 ++ xen/include/xeno/sched.h | 5 + .../arch/xeno/drivers/block/Makefile | 2 +- .../arch/xeno/drivers/block/xl_block.c | 6 + .../xeno/drivers/block/xl_physdisk_proc.c | 94 ++++++ .../xeno/drivers/block/xl_physdisk_proc.c~ | 94 ++++++ .../drivers/block/ll_rw_blk.c | 1 + 16 files changed, 835 insertions(+), 4 deletions(-) create mode 100644 tools/internal/physdev.h create mode 100644 tools/internal/xi_phys_grant.c create mode 100644 tools/internal/xi_phys_probe.c create mode 100644 tools/internal/xi_phys_revoke.c create mode 100644 xen/drivers/block/xen_physdisk.c create mode 100644 xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_physdisk_proc.c create mode 100644 xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_physdisk_proc.c~ diff --git a/.rootkeys b/.rootkeys index 5e185dc237..9f86143bbf 100644 --- a/.rootkeys +++ b/.rootkeys @@ -103,12 +103,16 @@ 3ee609b3Yr4aggmLSKmhiIzT8-nURA tools/internal/dom0_ops.h 3eb781fddjylXbsepjppUyIXa5lcaQ tools/internal/hypervisor_defs.h 3eb781fdKiQbgozBsgs_zzJQ9ubehw tools/internal/mem_defs.h +3f04589dFbtsbWWwAXq3I92UiAogCg tools/internal/physdev.h 3ec61e1bJCeJJu0SsptmDpA1xKvwvw tools/internal/rpm.spec 3eb781fdgbSkh2O6JQS-65Dz4n0ItQ tools/internal/xi_build.c 3eb781fdW1SAyiaC4mTsXq_9fRHh-A tools/internal/xi_create.c 3eb781fdcJ0fF7rWfzAOArW-x4-gwA tools/internal/xi_destroy.c 3ec43c5dmQxGDvgJJXbV1yLxT30Y1A tools/internal/xi_helper 3eb83c3bZeECmphOKOJxSu4Lo1LpBw tools/internal/xi_list +3f0458aaXhD8BQAggO81gv30RQ-ifA tools/internal/xi_phys_grant.c +3f0458aaJHmlzkDwf0qxEzAcjX55sg tools/internal/xi_phys_probe.c +3f0458aaVAbFSwptQbQAnDOiZlwQ3w tools/internal/xi_phys_revoke.c 3eb781fd8oRfPgH7qTh7xvgmwD6NgA tools/internal/xi_start.c 3eb781fd0Eo9K1jEFCSAVzO51i_ngg tools/internal/xi_stop.c 3eb781fd7211MZsLxJSiuy7W4KnJXg tools/internal/xi_vifinit @@ -194,6 +198,7 @@ 3ddb79beNQVrdGyoI4njXhgAjD6a4A xen/drivers/block/genhd.c 3ddb79beyWwLRP_BiM2t1JKgr_plEw xen/drivers/block/ll_rw_blk.c 3e4a8cb7RhubVgsPwO7cK0pgAN8WCQ xen/drivers/block/xen_block.c +3f045882spujO81dMl-fYWGiZ8WcPw xen/drivers/block/xen_physdisk.c 3e5d129asHNyZOjBKTkqs-9AFzxemA xen/drivers/block/xen_segment.c 3e9c248afxxsnAzIt2na7Ej24yNFzg xen/drivers/cdrom/Makefile 3e9c248ajUkn2W3n4vgm72Hp2ftZ8A xen/drivers/cdrom/cdrom.c @@ -481,6 +486,8 @@ 3e5a4e65pP5spJErBW69pJxSSdK9RA xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_block.c 3e67f822FOPwqHiaRKbrskgWgoNL5g xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_block.h 3e677190SjkzJIvFifRVeYpIZOCtYA xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_ide.c +3f045897EIYU5l5jxFBpeF1Z0ZOTwA xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_physdisk_proc.c +3f045a16wW57GFQ3r3Ta2cJOo1ierQ xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_physdisk_proc.c~ 3e677193nOKKTLJzcAu4SYdbZaia8g xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_scsi.c 3e676eb5RXnHzSHgA1BvM0B1aIm4qg xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_segment.c 3e5d129aDldt6geU2-2SzBae34sQzg xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_segment_proc.c diff --git a/tools/internal/Makefile b/tools/internal/Makefile index 417ffe7adb..8b50b410e8 100644 --- a/tools/internal/Makefile +++ b/tools/internal/Makefile @@ -4,13 +4,18 @@ XI_START = xi_start XI_STOP = xi_stop XI_DESTROY = xi_destroy XI_BUILD = xi_build +XI_PHYS_GRANT = xi_phys_grant +XI_PHYS_REVOKE = xi_phys_revoke -all: $(XI_CREATE).o $(XI_START).o $(XI_STOP).o $(XI_DESTROY).o $(XI_BUILD).o +all: $(XI_CREATE).o $(XI_START).o $(XI_STOP).o $(XI_DESTROY).o $(XI_BUILD).o \ + $(XI_PHYS_GRANT).o $(XI_PHYS_REVOKE).o $(CC) -o $(XI_CREATE) $(XI_CREATE).o $(CC) -o $(XI_BUILD) $(XI_BUILD).o $(CC) -o $(XI_START) $(XI_START).o $(CC) -o $(XI_STOP) $(XI_STOP).o $(CC) -o $(XI_DESTROY) $(XI_DESTROY).o + $(CC) -o $(XI_PHYS_GRANT) $(XI_PHYS_GRANT).o + $(CC) -o $(XI_PHYS_REVOKE) $(XI_PHYS_REVOKE).o $(XI_CREATE).o: $(XI_CREATE).c dom0_defs.h dom0_ops.h hypervisor_defs.h mem_defs.h $(CC) -c $(XI_CREATE).c @@ -27,8 +32,14 @@ $(XI_STOP).o: $(XI_STOP).c dom0_defs.h dom0_ops.h hypervisor_defs.h mem_defs.h $(XI_DESTROY).o: $(XI_DESTROY).c dom0_ops.h dom0_defs.h $(CC) -c $(XI_DESTROY).c +$(XI_PHYS_GRANT).o: $(XI_PHYS_GRANT).c physdev.h + $(CC) -c $(XI_PHYS_GRANT).c + +$(XI_PHYS_REVOKE).o: $(XI_PHYS_REVOKE).c physdev.h + $(CC) -c $(XI_PHYS_REVOKE).c + install: all - cp -a xi_list xi_vifinit xi_helper $(XI_CREATE) $(XI_BUILD) $(XI_START) $(XI_STOP) $(XI_DESTROY) ../../../install/bin + cp -a xi_list xi_vifinit xi_helper $(XI_CREATE) $(XI_BUILD) $(XI_START) $(XI_STOP) $(XI_DESTROY) $(XI_PHYSDEV_GRANT) $(XI_PHYS_REVOKE) ../../../install/bin chmod 755 ../../../install/bin/xi_list chmod 755 ../../../install/bin/xi_vifinit chmod 755 ../../../install/bin/xi_helper @@ -42,5 +53,5 @@ rpm: all rm -rf staging clean: - $(RM) *.o *.rpm $(XI_CREATE) $(XI_START) $(XI_STOP) $(XI_DESTROY) $(XI_BUILD) + $(RM) *.o *.rpm $(XI_CREATE) $(XI_START) $(XI_STOP) $(XI_DESTROY) $(XI_BUILD) $(XI_PHYSDEV_GRANT) diff --git a/tools/internal/physdev.h b/tools/internal/physdev.h new file mode 100644 index 0000000000..54a0120be1 --- /dev/null +++ b/tools/internal/physdev.h @@ -0,0 +1,26 @@ +#define XEN_BLOCK_PHYSDEV_GRANT 10 /* grant access to range of disk blocks */ +#define XEN_BLOCK_PHYSDEV_REVOKE 11 /* revoke access to range of disk blocks */ +#define XEN_BLOCK_PHYSDEV_PROBE 12 /* probe for a domain's physdev + accesses */ + +typedef struct xp_disk +{ + int mode; + int domain; + unsigned short device; + unsigned long start_sect; + unsigned long n_sectors; +} xp_disk_t; + +#define PHYSDISK_MAX_ACES_PER_REQUEST 254 +typedef struct { + int n_aces; + int domain; + int start_ind; + struct { + unsigned short device; + unsigned long start_sect; + unsigned long n_sectors; + unsigned mode; + } entries[PHYSDISK_MAX_ACES_PER_REQUEST]; +} physdisk_probebuf_t; diff --git a/tools/internal/xi_phys_grant.c b/tools/internal/xi_phys_grant.c new file mode 100644 index 0000000000..7912185066 --- /dev/null +++ b/tools/internal/xi_phys_grant.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include + +#include "physdev.h" + +int main(int argc, char *argv[]) +{ + xp_disk_t buf; + int fd; + + if (argc != 6) { + fprintf(stderr, "Usage: xi_physdev_grant \n"); + return 1; + } + + buf.mode = 0; + if (argv[1][0] == 'r') + buf.mode |= 1; + else if (argv[1][0] == 'w') + buf.mode |= 2; + if (argv[1][1] == 'r') + buf.mode |= 1; + else if (argv[1][1] == 'w') + buf.mode |= 2; + + buf.domain = atol(argv[2]); + buf.device = atol(argv[3]); + buf.start_sect = atol(argv[4]); + buf.n_sectors = atol(argv[5]); + + fd = open("/proc/xeno/dom0/phd", O_WRONLY); + if (fd < 0) { + fprintf(stderr, "Can\'t open /proc/xeno/dom0/phd: %s.\n", strerror(errno)); + return 1; + } + + write(fd, &buf, sizeof(buf)); + close(fd); + + return 0; +} diff --git a/tools/internal/xi_phys_probe.c b/tools/internal/xi_phys_probe.c new file mode 100644 index 0000000000..caa01d3604 --- /dev/null +++ b/tools/internal/xi_phys_probe.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include + +#include "physdev.h" + +int main(int argc, char *argv[]) +{ + physdisk_probebuf_t buf; + int fd; + int x; + + if (argc != 2) { + fprintf(stderr, "Usage: xi_phys_probe \n"); + return 1; + } + + fd = open("/proc/xeno/dom0/phd", O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Can\'t open /proc/xeno/dom0/phd: %s.\n", + strerror(errno)); + return 1; + } + + memset(&buf, 0, sizeof(buf)); + buf.n_aces = PHYSDISK_MAX_ACES_PER_REQUEST; + while (buf.n_aces == PHYSDISK_MAX_ACES_PER_REQUEST || + buf.n_aces == 0) { + buf.n_aces = PHYSDISK_MAX_ACES_PER_REQUEST; + buf.domain = atol(argv[1]); + read(fd, &buf, sizeof(buf)); + if (!buf.n_aces) + break; + + printf("Found %d ACEs\n", buf.n_aces); + + for (x = 0; x < buf.n_aces; x++) { + printf("%x:[%x,%x) : %x\n", buf.entries[x].device, + buf.entries[x].start_sect, + buf.entries[x].start_sect + buf.entries[x].n_sectors, + buf.entries[x].mode); + } + buf.start_ind += buf.n_aces; + } + return 0; +} diff --git a/tools/internal/xi_phys_revoke.c b/tools/internal/xi_phys_revoke.c new file mode 100644 index 0000000000..b4bf72833b --- /dev/null +++ b/tools/internal/xi_phys_revoke.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +#include "physdev.h" + +int main(int argc, char *argv[]) +{ + xp_disk_t buf; + int fd; + + if (argc != 5) { + fprintf(stderr, "Usage: xi_physdev_revoke \n"); + return 1; + } + + buf.domain = atol(argv[1]); + buf.device = atol(argv[2]); + buf.start_sect = atol(argv[3]); + buf.n_sectors = atol(argv[4]); + + fd = open("/proc/xeno/dom0/phd", O_WRONLY); + if (fd < 0) { + fprintf(stderr, "Can\'t open /proc/xeno/dom0/phd: %s.\n", strerror(errno)); + return 1; + } + + write(fd, &buf, sizeof(buf)); + close(fd); + + return 0; +} diff --git a/xen/common/domain.c b/xen/common/domain.c index b9804c6ebc..00edab32fe 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -52,6 +52,7 @@ struct task_struct *do_newdomain(unsigned int dom_id, unsigned int cpu) spin_lock_init(&p->blk_ring_lock); spin_lock_init(&p->page_lock); + spin_lock_init(&p->physdev_lock); p->shared_info = (void *)get_free_page(GFP_KERNEL); memset(p->shared_info, 0, PAGE_SIZE); @@ -62,6 +63,8 @@ struct task_struct *do_newdomain(unsigned int dom_id, unsigned int cpu) init_blkdev_info(p); + INIT_LIST_HEAD(&p->physdisk_aces); + SET_GDT_ENTRIES(p, DEFAULT_GDT_ENTRIES); SET_GDT_ADDRESS(p, DEFAULT_GDT_ADDRESS); @@ -303,6 +306,9 @@ void release_task(struct task_struct *p) */ destroy_blkdev_info(p); + /* Free up the physdisk access control info */ + destroy_physdisk_aces(p); + /* Free all memory associated with this domain. */ free_page((unsigned long)p->mm.perdomain_pt); UNSHARE_PFN(virt_to_page(p->shared_info)); diff --git a/xen/drivers/block/xen_block.c b/xen/drivers/block/xen_block.c index 07738f98bf..809dd6a701 100644 --- a/xen/drivers/block/xen_block.c +++ b/xen/drivers/block/xen_block.c @@ -104,6 +104,9 @@ static void dispatch_probe_seg(struct task_struct *p, int index); static void dispatch_debug_block_io(struct task_struct *p, int index); static void dispatch_create_segment(struct task_struct *p, int index); static void dispatch_delete_segment(struct task_struct *p, int index); +static void dispatch_grant_physdev(struct task_struct *p, int index); +static void dispatch_revoke_physdev(struct task_struct *p, int index); +static void dispatch_probe_physdev(struct task_struct *p, int index); static void make_response(struct task_struct *p, unsigned long id, unsigned short op, unsigned long st); @@ -396,6 +399,18 @@ static int do_block_io_op_domain(struct task_struct *p, int max_to_do) dispatch_delete_segment(p, i); break; + case XEN_BLOCK_PHYSDEV_GRANT: + dispatch_grant_physdev(p, i); + break; + + case XEN_BLOCK_PHYSDEV_REVOKE: + dispatch_revoke_physdev(p, i); + break; + + case XEN_BLOCK_PHYSDEV_PROBE: + dispatch_probe_physdev(p, i); + break; + default: DPRINTK("error: unknown block io operation [%d]\n", blk_ring->ring[i].req.operation); @@ -414,6 +429,115 @@ static void dispatch_debug_block_io(struct task_struct *p, int index) DPRINTK("dispatch_debug_block_io: unimplemented\n"); } +static void dispatch_probe_physdev(struct task_struct *p, int index) +{ + blk_ring_t *blk_ring = p->blk_ring_base; + unsigned long flags, buffer; + physdisk_probebuf_t *buf; + int result; + + if ( p->domain != 0 ) + { + result = 1; + goto out; + } + + buffer = blk_ring->ring[index].req.buffer_and_sects[0] & ~0x1FF; + + spin_lock_irqsave(&p->page_lock, flags); + if ( !__buffer_is_valid(p, buffer, sizeof(*buf), 1) ) + { + spin_unlock_irqrestore(&p->page_lock, flags); + result = 1; + goto out; + } + __lock_buffer(buffer, sizeof(*buf), 1); + spin_unlock_irqrestore(&p->page_lock, flags); + + buf = phys_to_virt(buffer); + result = xen_physdisk_probe(buf); + + unlock_buffer(p, buffer, sizeof(*buf), 1); + + out: + make_response(p, blk_ring->ring[index].req.id, + XEN_BLOCK_PHYSDEV_PROBE, result); +} + +static void dispatch_grant_physdev(struct task_struct *p, int index) +{ + blk_ring_t *blk_ring = p->blk_ring_base; + unsigned long flags, buffer; + xp_disk_t *xpd; + int result; + + if ( p->domain != 0 ) + { + DPRINTK("dispatch_grant_physdev called by dom%d\n", p->domain); + result = 1; + goto out; + } + + buffer = blk_ring->ring[index].req.buffer_and_sects[0] & ~0x1FF; + + spin_lock_irqsave(&p->page_lock, flags); + if ( !__buffer_is_valid(p, buffer, sizeof(xv_disk_t), 1) ) + { + DPRINTK("Bad buffer in dispatch_grant_physdev\n"); + spin_unlock_irqrestore(&p->page_lock, flags); + result = 1; + goto out; + } + __lock_buffer(buffer, sizeof(xv_disk_t), 1); + spin_unlock_irqrestore(&p->page_lock, flags); + + xpd = phys_to_virt(buffer); + result = xen_physdisk_grant(xpd); + + unlock_buffer(p, buffer, sizeof(xp_disk_t), 1); + + out: + make_response(p, blk_ring->ring[index].req.id, + XEN_BLOCK_PHYSDEV_GRANT, result); +} + +static void dispatch_revoke_physdev(struct task_struct *p, int index) +{ + blk_ring_t *blk_ring = p->blk_ring_base; + unsigned long flags, buffer; + xp_disk_t *xpd; + int result; + + if ( p->domain != 0 ) + { + DPRINTK("dispatch_grant_physdev called by dom%d\n", p->domain); + result = 1; + goto out; + } + + buffer = blk_ring->ring[index].req.buffer_and_sects[0] & ~0x1FF; + + spin_lock_irqsave(&p->page_lock, flags); + if ( !__buffer_is_valid(p, buffer, sizeof(xv_disk_t), 1) ) + { + DPRINTK("Bad buffer in dispatch_grant_physdev\n"); + spin_unlock_irqrestore(&p->page_lock, flags); + result = 1; + goto out; + } + __lock_buffer(buffer, sizeof(xv_disk_t), 1); + spin_unlock_irqrestore(&p->page_lock, flags); + + xpd = phys_to_virt(buffer); + result = xen_physdisk_revoke(xpd); + + unlock_buffer(p, buffer, sizeof(xp_disk_t), 1); + + out: + make_response(p, blk_ring->ring[index].req.id, + XEN_BLOCK_PHYSDEV_REVOKE, result); +} + static void dispatch_create_segment(struct task_struct *p, int index) { blk_ring_t *blk_ring = p->blk_ring_base; @@ -593,6 +717,12 @@ static void dispatch_rw_block_io(struct task_struct *p, int index) DPRINTK("bad device\n"); goto bad_descriptor; } + if (p->domain != 0 && + !xen_physdisk_access_okay(&phys_seg, p, operation)) { + DPRINTK("access denied\n"); + /* XXX not quite right, but close enough. */ + goto bad_descriptor; + } new_segs = 1; } diff --git a/xen/drivers/block/xen_physdisk.c b/xen/drivers/block/xen_physdisk.c new file mode 100644 index 0000000000..def17c5ced --- /dev/null +++ b/xen/drivers/block/xen_physdisk.c @@ -0,0 +1,301 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +#if 0 +#define DPRINTK printk +#else +#define DPRINTK(...) +#endif + +/* The idea is that, for each sector of each disk, each domain has two + bits, saying whether they can read the sector or write it. That + would take too much memory, so instead each process has a list of + (device, start, end, mode) quads which say what it has access to, + and we fake the logical view on top of that. */ +struct physdisk_ace { + struct list_head list; + + unsigned short device; + unsigned long start_sect; + unsigned long n_sectors; +#define PHYSDISK_MODE_R 1 +#define PHYSDISK_MODE_W 2 + int mode; +}; + +/* Operation is a blkdev constant i.e. READ, WRITE, ... */ +/* Must be called with p->physdev_lock held. */ +static struct physdisk_ace *find_ace(const struct task_struct *p, + unsigned short dev, + unsigned long sect, + int operation) +{ + struct list_head *cur_ace_head; + struct physdisk_ace *cur_ace; + + list_for_each(cur_ace_head, &p->physdisk_aces) { + cur_ace = list_entry(cur_ace_head, struct physdisk_ace, + list); + DPRINTK("Is [%lx, %lx) good for %lx?\n", + cur_ace->start_sect, cur_ace->start_sect + cur_ace->n_sectors, + sect); + if (sect >= cur_ace->start_sect && + sect < cur_ace->start_sect + cur_ace->n_sectors && + dev == cur_ace->device && + ((operation == READ && (cur_ace->mode & PHYSDISK_MODE_R)) || + (operation == WRITE && (cur_ace->mode & PHYSDISK_MODE_W)))) { + DPRINTK("Yes.\n"); + return cur_ace; + } else { + DPRINTK("No.\n"); + } + } + return NULL; +} + +/* Hold the lock on entry, it remains held on exit. */ +/* XXX we call kmalloc and kfree with GFP_KERNEL and a spinlock held + in here. That wouldn't be allowed under Linux, but, from reading + the source, it seems to be okay under Xen... */ +static void xen_physdisk_revoke_access(unsigned short dev, + unsigned long start_sect, + unsigned long n_sectors, + struct task_struct *p) +{ + /* Find every ace which intersects [start_sect, start_sect + + n_sectors] and either remove it completely or truncate it + down. */ + struct list_head *cur_ace_head; + struct physdisk_ace *cur_ace, *new_ace; + unsigned long kill_zone_end, ace_end; + + kill_zone_end = start_sect + n_sectors; + list_for_each(cur_ace_head, &p->physdisk_aces) { + cur_ace = list_entry(cur_ace_head, struct physdisk_ace, + list); + ace_end = cur_ace->start_sect + cur_ace->n_sectors; + if (cur_ace->start_sect > kill_zone_end || + ace_end < start_sect) + continue; + + if (cur_ace->start_sect >= start_sect && + ace_end < kill_zone_end) { + /* ace entirely within kill zone -> kill it */ + list_del(cur_ace_head); + cur_ace_head = cur_ace_head->next; + kfree(cur_ace); + } else if (ace_end < kill_zone_end) { + /* ace start before kill start, ace end in kill zone, + move ace end. */ + cur_ace->n_sectors = start_sect - cur_ace->start_sect; + } else if (cur_ace->start_sect >= start_sect) { + /* ace start after kill start, ace end outside kill zone, + move ace start. */ + cur_ace->start_sect = kill_zone_end; + cur_ace->n_sectors = ace_end - cur_ace->start_sect; + } else { + /* The fun one: the kill zone entirely includes the ace. */ + /* Cut the current ace down to just the bit before the kzone, + create a new ace for the bit just after it. */ + new_ace = kmalloc(sizeof(*cur_ace), GFP_KERNEL); + new_ace->device = dev; + new_ace->start_sect = kill_zone_end; + new_ace->n_sectors = ace_end - kill_zone_end; + new_ace->mode = cur_ace->mode; + + cur_ace->n_sectors = start_sect - cur_ace->start_sect; + + list_add(&new_ace->list, cur_ace_head); + cur_ace_head = new_ace->list.next; + } + } +} + +/* Hold the lock on entry, it remains held on exit. */ +static int xen_physdisk_grant_access(unsigned short dev, + unsigned long start_sect, + unsigned long n_sectors, + int mode, + struct task_struct *p) +{ + struct physdisk_ace *cur_ace; + + /* Make sure it won't overlap with any existing ACEs. */ + /* XXX this isn't quite right if the domain already has read access + and we try to grant write access, or vice versa. */ + xen_physdisk_revoke_access(dev, start_sect, n_sectors, p); + + cur_ace = kmalloc(sizeof(*cur_ace), GFP_KERNEL); + cur_ace->device = dev; + cur_ace->start_sect = start_sect; + cur_ace->n_sectors = n_sectors; + cur_ace->mode = mode; + + list_add_tail(&cur_ace->list, &p->physdisk_aces); + + return 0; +} + +static void xen_physdisk_probe_access(physdisk_probebuf_t *buf, + struct task_struct *p) +{ + int max_aces; + int n_aces; + struct list_head *cur_ace_head; + struct physdisk_ace *cur_ace; + int x; + + max_aces = buf->n_aces; + n_aces = 0; + list_for_each(cur_ace_head, &p->physdisk_aces) { + if (x < buf->start_ind) { + x++; + continue; + } + cur_ace = list_entry(cur_ace_head, struct physdisk_ace, + list); + buf->entries[n_aces].device = cur_ace->device; + buf->entries[n_aces].start_sect = cur_ace->start_sect; + buf->entries[n_aces].n_sectors = cur_ace->n_sectors; + buf->entries[n_aces].mode = cur_ace->mode; + n_aces++; + if (n_aces >= max_aces) + break; + } + buf->n_aces = n_aces; + printk("Found a total of %x aces (max %x).\n", n_aces, max_aces); +} + +int xen_physdisk_grant(xp_disk_t *xpd_in) +{ + struct task_struct *p; + xp_disk_t *xpd = map_domain_mem(virt_to_phys(xpd_in)); + int res; + + p = current; + DPRINTK("Have current.\n"); + DPRINTK("Target domain %x\n", xpd->domain); + + do { + p = p->next_task; + } while (p != current && p->domain != xpd->domain); + if (p->domain != xpd->domain) { + DPRINTK("Bad domain! No biscuit!\n"); + res = 1; + goto out; + } + spin_lock(&p->physdev_lock); + res = xen_physdisk_grant_access(xpd->device, + xpd->start_sect, + xpd->n_sectors, + xpd->mode, + p); + spin_unlock(&p->physdev_lock); + + out: + unmap_domain_mem(xpd); + return res; +} + +int xen_physdisk_revoke(xp_disk_t *xpd_in) +{ + struct task_struct *p; + xp_disk_t *xpd = map_domain_mem(virt_to_phys(xpd_in)); + int res; + + p = current; + + do { + p = p->next_task; + } while (p != current && p->domain != xpd->domain); + if (p->domain != xpd->domain) { + res = 1; + goto out; + } + spin_lock(&p->physdev_lock); + xen_physdisk_revoke_access(xpd->device, + xpd->start_sect, + xpd->n_sectors, + p); + spin_unlock(&p->physdev_lock); + res = 0; + out: + unmap_domain_mem(xpd); + return res; +} + +int xen_physdisk_probe(physdisk_probebuf_t *buf_in) +{ + struct task_struct *p; + physdisk_probebuf_t *buf = map_domain_mem(virt_to_phys(buf_in)); + int res; + + p = current; + do { + p = p->next_task; + } while (p != current && p->domain != buf->domain); + if (p->domain != buf->domain) { + res = 1; + goto out; + } + printk("initially %x aces.\n", buf->n_aces); + spin_lock(&p->physdev_lock); + xen_physdisk_probe_access(buf, p); + spin_unlock(&p->physdev_lock); + printk("%x aces.\n", buf->n_aces); + res = 0; + out: + unmap_domain_mem(buf); + return res; +} + +int xen_physdisk_access_okay(phys_seg_t *pseg, struct task_struct *p, + int operation) +{ + struct physdisk_ace *cur_ace; + unsigned long sect; + + DPRINTK("Checking access for domain %d, start sect %d, length %d.\n", + p->domain, pseg->sector_number, pseg->nr_sects); + + for (sect = pseg->sector_number; + sect < pseg->sector_number + pseg->nr_sects; + ) { + /* XXX this would be a lot faster if the aces were sorted on start + address. Also in revoke_access. */ + spin_lock(&p->physdev_lock); + cur_ace = find_ace(p, pseg->dev, sect, operation); + spin_unlock(&p->physdev_lock); + if (!cur_ace) { + /* Default closed. */ + return 0; + } + sect += MAX(cur_ace->n_sectors, pseg->nr_sects + pseg->sector_number - sect); + } + return 1; +} + +void destroy_physdisk_aces(struct task_struct *p) +{ + struct list_head *cur_ace_head, *next_head; + struct physdisk_ace *cur_ace; + + spin_lock(&p->physdev_lock); /* We never release this again. */ + + for (cur_ace_head = p->physdisk_aces.next; + cur_ace_head != &p->physdisk_aces; + cur_ace_head = next_head) { + cur_ace = list_entry(cur_ace_head, struct physdisk_ace, + list); + next_head = cur_ace_head->next; + kfree(cur_ace); + } +} diff --git a/xen/include/hypervisor-ifs/block.h b/xen/include/hypervisor-ifs/block.h index 947f87abe3..c60b4ac0e3 100644 --- a/xen/include/hypervisor-ifs/block.h +++ b/xen/include/hypervisor-ifs/block.h @@ -47,6 +47,10 @@ #define XEN_BLOCK_SEG_CREATE 7 /* create segment (vhd) */ #define XEN_BLOCK_SEG_DELETE 8 /* delete segment (vhd) */ #define XEN_BLOCK_PROBE_SEG 9 /* get vhd config from hypervisor */ +#define XEN_BLOCK_PHYSDEV_GRANT 10 /* grant access to range of disk blocks */ +#define XEN_BLOCK_PHYSDEV_REVOKE 11 /* revoke access to range of disk blocks */ +#define XEN_BLOCK_PHYSDEV_PROBE 12 /* probe for a domain's physdev + accesses */ /* NB. Ring size must be small enough for sizeof(blk_ring_t) <= PAGE_SIZE. */ #define BLK_RING_SIZE 64 @@ -139,4 +143,26 @@ typedef struct xv_disk xv_extent_t extents[XEN_MAX_DISK_COUNT]; /* arbitrary reuse of constant */ } xv_disk_t; +typedef struct xp_disk +{ + int mode; + int domain; + unsigned short device; + unsigned long start_sect; + unsigned long n_sectors; +} xp_disk_t; + +#define PHYSDISK_MAX_ACES_PER_REQUEST 254 +typedef struct { + int n_aces; + int domain; + int start_ind; + struct { + unsigned short device; + unsigned long start_sect; + unsigned long n_sectors; + unsigned mode; + } entries[PHYSDISK_MAX_ACES_PER_REQUEST]; +} physdisk_probebuf_t; + #endif diff --git a/xen/include/xeno/sched.h b/xen/include/xeno/sched.h index 7d9e2fcbd2..351afa5e8d 100644 --- a/xen/include/xeno/sched.h +++ b/xen/include/xeno/sched.h @@ -133,6 +133,11 @@ struct task_struct unsigned int blk_resp_prod; /* (private version of) response producer */ struct list_head blkdev_list; spinlock_t blk_ring_lock; + struct list_head physdisk_aces; /* physdisk_ace structures + describing what bits of disk + the process can do raw access + to. */ + spinlock_t physdev_lock; segment_t *segment_list[XEN_MAX_SEGMENTS]; /* xvd */ /* VM */ diff --git a/xenolinux-2.4.21-sparse/arch/xeno/drivers/block/Makefile b/xenolinux-2.4.21-sparse/arch/xeno/drivers/block/Makefile index 6423104172..c6997d2717 100644 --- a/xenolinux-2.4.21-sparse/arch/xeno/drivers/block/Makefile +++ b/xenolinux-2.4.21-sparse/arch/xeno/drivers/block/Makefile @@ -1,3 +1,3 @@ O_TARGET := blk.o -obj-y := xl_block.o xl_ide.o xl_scsi.o xl_segment.o xl_segment_proc.o +obj-y := xl_block.o xl_ide.o xl_scsi.o xl_segment.o xl_segment_proc.o xl_physdisk_proc.o include $(TOPDIR)/Rules.make diff --git a/xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_block.c b/xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_block.c index d3e09eb52c..b204aa2586 100644 --- a/xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_block.c +++ b/xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_block.c @@ -307,6 +307,9 @@ static int hypervisor_request(unsigned long id, { case XEN_BLOCK_SEG_CREATE: case XEN_BLOCK_SEG_DELETE: + case XEN_BLOCK_PHYSDEV_GRANT: + case XEN_BLOCK_PHYSDEV_REVOKE: + case XEN_BLOCK_PHYSDEV_PROBE: case XEN_BLOCK_PROBE_BLK: case XEN_BLOCK_PROBE_SEG: if ( RING_FULL ) return 1; @@ -478,6 +481,9 @@ static void xlblk_response_int(int irq, void *dev_id, struct pt_regs *ptregs) case XEN_BLOCK_SEG_DELETE: case XEN_BLOCK_PROBE_SEG: case XEN_BLOCK_PROBE_BLK: + case XEN_BLOCK_PHYSDEV_GRANT: + case XEN_BLOCK_PHYSDEV_REVOKE: + case XEN_BLOCK_PHYSDEV_PROBE: if ( bret->status ) printk(KERN_ALERT "Bad return from blkdev control request\n"); xlblk_control_msg_pending = 0; diff --git a/xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_physdisk_proc.c b/xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_physdisk_proc.c new file mode 100644 index 0000000000..6b4df31025 --- /dev/null +++ b/xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_physdisk_proc.c @@ -0,0 +1,94 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static struct proc_dir_entry *phd; + +extern int xenolinux_control_msg(int operration, char *buffer, int size); + +static ssize_t proc_read_phd(struct file * file, char * buff, size_t size, loff_t * off) +{ + physdisk_probebuf_t *buf; + int res; + + if (size != sizeof(physdisk_probebuf_t)) + return -EINVAL; + + buf = kmalloc(sizeof(physdisk_probebuf_t), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, buff, size)) { + kfree(buf); + return -EFAULT; + } + + printk("max aces 1 %x\n", buf->n_aces); + + res = xenolinux_control_msg(XEN_BLOCK_PHYSDEV_PROBE, (void *)buf, + sizeof(physdisk_probebuf_t)); + + printk("max aces %x\n", buf->n_aces); + + if (res) + res = -EINVAL; + else { + res = sizeof(physdisk_probebuf_t); + if (copy_to_user(buff, buf, sizeof(physdisk_probebuf_t))) { + res = -EFAULT; + } + } + kfree(buf); + return res; +} + +static int proc_write_phd(struct file *file, const char *buffer, + size_t count, loff_t *ignore) +{ + char *local; + int res; + + if (count != sizeof(xp_disk_t)) + return -EINVAL; + + local = kmalloc(count + 1, GFP_KERNEL); + if (!local) + return -ENOMEM; + if (copy_from_user(local, buffer, count)) { + res = -EFAULT; + goto out; + } + local[count] = 0; + + res = xenolinux_control_msg(XEN_BLOCK_PHYSDEV_GRANT, local, count); + if (res == 0) + res = count; + else + res = -EINVAL; + out: + kfree(local); + return res; +} + +static struct file_operations proc_phd_fops = { + read : proc_read_phd, + write : proc_write_phd +}; + +int __init xlphysdisk_proc_init(void) +{ + phd = create_proc_entry("xeno/dom0/phd", 0644, NULL); + if (!phd) { + panic("Can\'t create phd proc entry!\n"); + } + phd->data = NULL; + phd->proc_fops = &proc_phd_fops; + phd->owner = THIS_MODULE; + + return 0; +} diff --git a/xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_physdisk_proc.c~ b/xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_physdisk_proc.c~ new file mode 100644 index 0000000000..6c76bd5887 --- /dev/null +++ b/xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_physdisk_proc.c~ @@ -0,0 +1,94 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static struct proc_dir_entry *phd; + +extern int xenolinux_control_msg(int operration, char *buffer, int size); + +static ssize_t proc_read_phd(struct file * file, char * buff, size_t size, loff_t * off) +{ + physdisk_probebuf_t *buf; + int res; + + if (size != sizeof(physdisk_probebuf_t)) + return -EINVAL; + + buf = kmalloc(sizeof(physdisk_probebuf_t), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, buff, size)) { + kfree(buf); + return -EFAULT; + } + + printk("max aces %x\n", buf->n_aces); + + res = xenolinux_control_msg(XEN_BLOCK_PHYSDEV_PROBE, (void *)buf, + sizeof(physdisk_probebuf_t)); + + printk("max aces %x\n", buf->n_aces); + + if (res) + res = -EINVAL; + else { + res = sizeof(physdisk_probebuf_t); + if (copy_to_user(buff, buf, sizeof(physdisk_probebuf_t))) { + res = -EFAULT; + } + } + kfree(buf); + return res; +} + +static int proc_write_phd(struct file *file, const char *buffer, + size_t count, loff_t *ignore) +{ + char *local; + int res; + + if (count != sizeof(xp_disk_t)) + return -EINVAL; + + local = kmalloc(count + 1, GFP_KERNEL); + if (!local) + return -ENOMEM; + if (copy_from_user(local, buffer, count)) { + res = -EFAULT; + goto out; + } + local[count] = 0; + + res = xenolinux_control_msg(XEN_BLOCK_PHYSDEV_GRANT, local, count); + if (res == 0) + res = count; + else + res = -EINVAL; + out: + kfree(local); + return res; +} + +static struct file_operations proc_phd_fops = { + read : proc_read_phd, + write : proc_write_phd +}; + +int __init xlphysdisk_proc_init(void) +{ + phd = create_proc_entry("xeno/dom0/phd", 0644, NULL); + if (!phd) { + panic("Can\'t create phd proc entry!\n"); + } + phd->data = NULL; + phd->proc_fops = &proc_phd_fops; + phd->owner = THIS_MODULE; + + return 0; +} diff --git a/xenolinux-2.4.21-sparse/drivers/block/ll_rw_blk.c b/xenolinux-2.4.21-sparse/drivers/block/ll_rw_blk.c index 411b6def8b..60f5584e2f 100644 --- a/xenolinux-2.4.21-sparse/drivers/block/ll_rw_blk.c +++ b/xenolinux-2.4.21-sparse/drivers/block/ll_rw_blk.c @@ -1505,6 +1505,7 @@ int __init blk_dev_init(void) xlblk_init(); xlseg_init(); xlseg_proc_init(); + xlphysdisk_proc_init(); #endif return 0; -- 2.30.2